# -*- coding: utf-8 -*-
import datetime
import decimal
import os
import time
import zipfile
from collections.abc import Iterable
import copy
from tempfile import NamedTemporaryFile
from typing import Any
from typing import List
from urllib.parse import quote
from fastapi.responses import Response
from openpyxl import Workbook
from openpyxl.worksheet.worksheet import Worksheet
from orjson import dumps
from pydantic import BaseModel, parse_obj_as
from sqlalchemy import Row
from log import log
from .myJsonHandler import orjson_dumps
import re



class RespResult(BaseModel):
    success: bool
    message: str
    code: int
    result: object | List[object] | None



def get_current_timestamp():
    return datetime.datetime.now().timestamp()


def get_current_time():
    now = datetime.datetime.now()
    # 格式化当前日期为 YYYY-MM-DD 格式
    formatted_date = now.strftime("%Y-%m-%d %H:%M:%S")
    return formatted_date




def is_iterable(obj):
    return isinstance(obj, Iterable) and not isinstance(obj, str)
# def is_iterable2(obj):
#     try:
#         iter(obj)
#         return True
#     except TypeError:
#         return False

def toPydantic(source, schema):
    # print(source)
    # print(inspect.isclass(source))
    # print(isinstance(source, Db_Base))
    if isinstance(source, list):
        return [toPydantic(s, schema) for s in source]
    else:
        if schema:
            return schema.from_orm(source)
        else:
            return parse_obj_as(schema, source)
            # return parse_obj_as(List[schema], source)
            # model_obj = model(** source.__dict__)
            # if inspect.isclass(source) and isinstance(source, SqlBase):


def result(message: str | None = "操作成功", success: bool = True, status: int = 200, data: Any = None,
           schema: Any = None):
    if schema and issubclass(schema, BaseModel):
        print('is valid schema')
        data_obj = toPydantic(data, schema)
    else:
        print('is invalid schema')
        data_obj = data

    res = RespResult(
        success=success,
        message=message,
        code=status,
        result=data_obj
    )
    return res


def remove_empty_values(data, exclude_null, and_exclude_empty_obj, include, exclude):
    if isinstance(data, dict):
        return {k: remove_empty_values(v, exclude_null, and_exclude_empty_obj, include, exclude) for k, v in data.items()
                if (not exclude_null or v or v == 0 or v == False or (not and_exclude_empty_obj and (v == [] or v == {})))
                and (not include or (include and k in include))
                and (not exclude or (exclude and k not in exclude))
                }
    elif isinstance(data, list):
        return [remove_empty_values(item, exclude_null, and_exclude_empty_obj, include, exclude) for item in data if item or item == 0 or item == False]
    else:
        return data


def has_func(obj, func):
    return hasattr(obj, func) and callable(getattr(obj, func))


# 递归解析对象集群
def parse_obj(obj):
    if not obj:
        return obj
    elif isinstance(obj, Row):
        return dict(obj._asdict())
    elif isinstance(obj, decimal.Decimal):
        return float(obj)  #
    elif isinstance(obj, list):
        return [parse_obj(item) for item in obj]
    elif has_func(obj, 'to_dict'):
        return obj.to_dict()
    elif isinstance(obj, datetime.datetime):
        return obj.strftime("%Y-%m-%d %H:%M:%S")
    else:
        return obj


def json_result(message: str | None = "操作成功", success: bool = True, status: int = 200,
                data: Any = None, exclude_null=True, and_exclude_empty_obj=False, include: set = None, exclude: set = None, use_serializer=False) -> bytes:
    # log.info("original data: {0}", data)
    if exclude is None:
        exclude = {}
    if use_serializer:
        log.info("orjson_dumps use_serializer....")
        content = orjson_dumps(dict(
            success=success,
            message=message,
            code=status,
            result=data
        ))
    else:
        res = parse_obj(data)
        log.info("res:{0}", type(res))
        # 去空值处理
        if res:
            res = remove_empty_values(res, exclude_null, and_exclude_empty_obj, include, exclude)

        content = dumps(dict(
            success=success,
            message=message,
            code=status,
            result=res
        ))

    return content


def json_reps(content: bytes):
    return Response(
        content=content,
        media_type="application/json; charset=UTF-8",
    )


def json_result_reps(message: str | None = "操作成功", success: bool = True, status: int = 200,
                     data: Any = None, exclude_null=True, exclude_empty_obj=False, include: set = None, exclude: set = None, use_serializer=False):
    return json_reps(
        json_result(
            message,
            success,
            status,
            data,
            exclude_null,
            exclude_empty_obj,
            include,
            exclude,
            use_serializer
        ))


def download_zip(content: bytes, filename: str):
    response = Response(content=content, media_type="application/zip")
    encoded_filename = quote(filename.encode('utf-8'))
    content_disposition = f"attachment; filename*=UTF-8''{encoded_filename}"
    response.headers["Content-Disposition"] = content_disposition
    return response


def download_file_stream(content: bytes, filename: str):
    header = {}
    encoded_filename = quote(filename.encode('utf-8'))
    content_disposition = f"attachment; filename*=UTF-8''{encoded_filename}"
    header.update({'Content-Type': 'application/octet-stream'})
    header.update({f'Content-Disposition': content_disposition})
    return Response(
        content=content,
        headers=header
    )


def dateFormat(date_str, format_str="%Y-%m-%d"):
    try:
        today = datetime.datetime.now()
        # 解析日期（默认当前年）
        parsed_date = datetime.datetime.strptime(date_str, "%m.%d")
        # 使用当前年构造完整日期
        current_year_date = parsed_date.replace(year=today.year)
        # 计算日期差值（考虑跨年情况）
        delta = current_year_date - today
        # 如果日期比当前晚 6 个月以上，则用去年
        if delta > datetime.timedelta(days=180):
            adjusted_date = current_year_date.replace(year=today.year - 1)
        # 如果日期比当前早 6 个月以上，则用明年
        elif delta < datetime.timedelta(days=-180):
            adjusted_date = current_year_date.replace(year=today.year + 1)
        else:
            adjusted_date = current_year_date
        return adjusted_date.strftime(format_str)
    except ValueError:
        # 如果不是 %m.%d 格式，返回原字符
        return date_str

async def zip_files(files: list, file_suffix='.xlsx') -> bytes:
    dest_file = None
    isDelete = True
    if os.name == 'nt':
        if os.path.isdir("e:\\tmp\\"):
            dest_file = "e:\\tmp\\" + str(int(time.time())) +file_suffix
        isDelete = False
    with NamedTemporaryFile(delete=isDelete) as temp_zip_file:
        with zipfile.ZipFile(temp_zip_file, 'w') as zip_file:
            # 创建多个Excel文件
            for f in files:
                obj, filename = f.values()
                # print(wb, filename)
                with NamedTemporaryFile(suffix=file_suffix) as temp_excel_file:
                    dest_file = dest_file or temp_excel_file.name
                    if isinstance(obj, Workbook):
                        obj.save(dest_file)
                    # 重新打开临时文件以读取内容，并添加到ZIP文件中
                    with open(dest_file, 'rb') as excel_file:
                        # zip_file.write(excel_file, f.filename)
                        data = excel_file.read()
                        zip_file.writestr(filename, data)
        # 将ZIP文件的内容读取到内存中
        temp_zip_file.seek(0)
        zip_content = temp_zip_file.read()
        #temp_zip_file.close()
        return zip_content

def parse_wrapper(excel_file, **kwargs):
    print(kwargs)
    print(f"{kwargs['name']},begin...")
    df = excel_file.parse(**{k: v for k, v in kwargs.items() if k not in ['name', 'path']})
    return df

# files = [ {"name": 'sample', "path": filePath, "sheet_name": 0}]
def ExcelFiles(files: list, this_pd=None):
    excels = {}
    dfs = {}
    for f in files:
        excel_ID = str(hash(f['path']))
        if excel_ID not in excels:
            excels[excel_ID] = []
        excels[excel_ID].append(f)
    # Create an ExcelFile object, a list for per value
    for sheets in excels.values():
        # using many times at one opening of excel file
        excel_file = this_pd.ExcelFile(sheets[0]['path'], engine='openpyxl')
        # Read a specific sheet and specify columns to read
        # You can specify columns by their names or by their indices
        dfs.update({sheet['name']: parse_wrapper(excel_file, **sheet) for sheet in sheets})
    print("ends all...")
    return dfs

def is_number(string):
    pattern = re.compile(r'^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$')
    return bool(pattern.match(string))

def ws_replace(ws, replacements):
    for row in ws.iter_rows(min_row=1, max_row=100, min_col=1, max_col=25):
        for cell in row:
            if cell.data_type == "s" and "{{" in str(cell.value):
                for old_text, new_text in replacements.items():
                    placeholder = f'{{{{{old_text}}}}}'
                    if not isinstance(new_text, str) and cell.value==placeholder:  #此时不是文本类型，不能replace
                        cell.value = new_text
                    elif isinstance(new_text, str) and placeholder in str(cell.value):
                        cell.value = str(cell.value).replace(placeholder, new_text)

def is_placeholder_tpl(ws, pattern:re.Pattern):
    for row in ws.iter_rows(min_row=1, max_row=100, min_col=1, max_col=25):
        for cell in row:
            if cell.data_type == "s" and pattern.search(str(cell.value)):
                return True


def copy_cells_by_pattern(tpl_sheet: Worksheet, new_sheet: Worksheet):
    # 正则表达式：匹配严格被[]包裹的内容，且括号内至少有一个字符
    pattern = re.compile(r'\[\[(.*?)\]\]')
    # 遍历所有单元格
    for row in range(1, tpl_sheet.max_row + 1):
        for col in range(1, tpl_sheet.max_column + 1): # tpl_sheet
            cell = tpl_sheet.cell(row=row, column=col)
            cell_value = cell.value
            cell_font = cell.font
            cell_alignment = cell.alignment
            # 检查单元格值是否为字符串且符合格式
            if isinstance(cell_value, str):
                match = pattern.fullmatch(cell_value)
                # 如果完全匹配[xxx]格式
                if match:
                    # 提取括号内的内容（去除括号）
                    cleaned_value = match.group(1)
                    # 复制到新工作表的相同位置
                    new_cell = new_sheet.cell(row=row, column=col) # new_sheet
                    new_cell.value = cleaned_value
                    # 复制单元格样式（可选）
                    new_cell.font = copy.copy(cell_font)
                    new_cell.alignment =  copy.copy(cell_alignment)
